package com.jt.auth.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * spring security 配置类，此类中要配置
 *   1）加密对象
 *   2）配置认证规则
 *   3)当我们在执行登录操作时（了解）：
 *      1：Filer（过滤器）
 *      2：AuthenticationManager（认证管理器）
 *      3：AuthenticationProvider（认证服务处理器）
 *      4：UserDetailsService（负责用户信息的获取及封装）
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**初始化密码加密对象*/
    //初始化加密对象
    //此对象提供了一种不可逆的加密方式，相对于md5方式会更加安全
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){

        return new BCryptPasswordEncoder();

    }

    /**
     * 定义认证管理器对象，这个对象负责完成用户信息的认证
     * 即判定用户身份信息的合法性，在基于oauth2协议完成认证时，
     * 需要此对象，所以这里讲此对象拿出来交给spring管理
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        return super.authenticationManagerBean();
    }


    /**配置认证规则*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //super.configure(http);
        //1.禁用跨域攻击（先这么写）
        http.csrf().disable();

        //2.旅行所有资源的访问
        //http.authorizeRequests().anyRequest().permitAll();
        http.authorizeRequests().antMatchers("/login/**").authenticated();

        //3.自定义定义登录成功和失败以后的处理逻辑(可选)
        //假如没有如下设置登录成功会显示404
        http.formLogin().successHandler(successHandler())
                        .failureHandler(failureHandler());

    }

    //定义认证成功以后的处理器
    @Bean
    public AuthenticationSuccessHandler successHandler(){

//        return new AuthenticationSuccessHandler() {
//            @Override
//            public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
//
//            }
//        };

        //lambda
        return (request,response,authentication)->{

            //构建map对象封装到要响应到客户端的数据
            Map<String,Object> map = new HashMap<>();
            map.put("state",200);
            map.put("message","login ok");

            //将map对象转为json格式字符串并写道客户端
            writeJsonToClient(response,map);

        };

    }

    //定义认证成失败以后的处理器
    @Bean
    public AuthenticationFailureHandler failureHandler(){

        return (request,response, exception)-> {

            //1.构建map对象,封装响应数据
            Map<String,Object> map=new HashMap<>();
            map.put("state",500);
            map.put("message","login failure");

            //2.将map对象写到客户端
            writeJsonToClient(response,map);
        };

    }

    private void writeJsonToClient(HttpServletResponse response,
                                   Map<String,Object> map) throws IOException{
        String json = new ObjectMapper().writeValueAsString(map);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(json);
        out.flush();
    }

}
